package itsecurity.hash.roque;

import itsecurity.collision.CollisionFinder;

import utils.*;
/**
 * Implements the hashing function described in DaviesMeyerDES,
 * but does not include padding. Used to produce birthday bits for given 
 * two byte-arrays.
 */
public class DaviesMeyerDESRoque {
	public static final int DES = 0;

	/**
	 * TODO: how to inject bday bits to cert? ATM this is done manually!
	 * Does DES-hash in Davies-Meyer mode for given plain text AND
	 * birthday bits that has been found and added to the end of the given 
	 * byte array.
	 * @param data plain texts, HAS TO BE DIVIDABLE BY 7!!!
	 * @throws Exception TODO: more specific Exception division?
	 */
	public void doHash (byte[] data, byte [] data2) throws Exception {
		byte[] iv1 = new byte[8];
		byte[] iv2 = new byte[8];
		byte[] input = new byte[8];
		byte[] iv = {(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
								(byte) 0x93, (byte) 0x18, (byte) 0x90};
				
		byte[] key = new byte[7];//key=next plaintext block (with parity bits)
		//NO PADDING!!  data = padData(data);
		input=iv;
//		System.out.println("\nIHVs for data1: ");
		for (int i=0; i<data.length; i+=7) {				
				System.arraycopy(data, i, key, 0, 7);
//				if (Arrays.equals(key, publicKeyStart)) {
//					System.out.println("Found public key!");
//				}
				key = addParityBits(key);
//				System.out.println(iaik.utils.Util.toString(input));
				byte[] orig = input;
				input = BitOperator.doXOR(itsecurity.hash.DES.encrypt(input, key), orig);
				input[7]=(byte)0;
			
		}
		System.out.println("\niv1 for birthday bit finding: "+iaik.utils.Util.toString(input));
		System.arraycopy(input, 0, iv1, 0, 8);
		
//		data2 = padData(data2);
		input=iv;
//		System.out.println("\nIHVs for data2: ");
		for (int i=0; i<data.length; i+=7) {				
				System.arraycopy(data, i, key, 0, 7);
				key = addParityBits(key);
//				System.out.println(iaik.utils.Util.toString(input));
				byte[] orig = input;
				input = BitOperator.doXOR(itsecurity.hash.DES.encrypt(input, key), orig);
				input[7]=(byte)0;
			
		}
		System.out.println("iv2 for birthday bit finding: "+iaik.utils.Util.toString(input));
		System.arraycopy(input, 0, iv2, 0, 8);
		
		CollisionFinder finder = new CollisionFinder(iv1, iv2);
		finder.findCycle();
		
		byte [] bdbits1 = finder.getLastTortoise();
		byte [] bdbits2 = finder.getLastHare();
		
		System.out.println("\nBday bits:+\n" +
				"1: "+iaik.utils.Util.toString(bdbits1) +
				"\n2: "+iaik.utils.Util.toString(bdbits2));
		

	}
	
	/**
	 * If number of 1-bits in a 7-bit block saved from input to output array
	 * is even, sets next bit to 1, else to 0. Repeats for all bytes of input array.
	 * @param input 7 bytes (56 bits). 
	 * @return 8-byte array (input with parity bits).
	 */
	private byte[] addParityBits(byte[] input) {
		byte[] parities = new byte[8];
		for (int i=0;i<=7;i++) {
			int ones=0;
			for (int j=0;j<7;j++) {
				int bit = BitOperator.getBit(input, i*7+j);
				if (bit>0) {
					parities=BitOperator.setBit(parities, i*8+j, bit);
					ones++;
				}
			}
			if (ones%2==0)
				parities=BitOperator.setBit(parities, 8*i+7, 1);
//			else
//				parities=BitOperator.setBit(parities, 8*(i+1)-1, 1);
		}
		return parities;
	}
	
}
